#pragma once

#include <iostream>
#include <string>
#include <ctemplate/template.h>

#include "oj_model.hpp"
// #include "oj_model2.hpp"

namespace ns_view
{
    using namespace ns_model;

    const std::string template_path = "./template_html/";

    class View
    {
    public:
        View(){}
        ~View(){}
    public:
        // 这个函数就用来做具体的渲染工作
        void AllExpandHtml(const vector<struct Question> &questions, std::string *html)
        {
            // questions是一个数组，里面存的是一个个用struct Question来描述的问题
            // html是一个输出型参数，用来存储渲染后的html内容

            // 题目的编号 题目的标题 题目的难度
            // 推荐使用表格显示
            // 1. 形成路径
            std::string src_html = template_path + "all_questions.html";
            // 2. 形成数据字典
            ctemplate::TemplateDictionary root("all_questions");

            // 一次循环渲染一个问题
            for (const auto& q : questions)
            {
                // 我们想要达到的目的是，把该问题对应html语句中的{{number}}，替换成它实际的问题编号（存储在Question::number中）
                // 为此我们首先得将{"number", q.number}这一键值对放入数据字典中，构建好映射关系之后，后面Expand函数去做具体替换
                // 但是现在有一个问题，就是问题的属性构成是相同的，但是问题不止一个，假如说我数据字典中的key="number"，请问你要换成问题1的编号，还是问题2的编号呢？
                    // 有的人可能会说，问题1的key就命名成number1，问题2的key我就命名成number2，这样不就一一对应了吗？这是绝大多数人都会想到的解决方案
                    // 但是这个解决方案也有一个问题，就是我命名的工作量就很大呀，然后你还得专门另申请一块空间出来存这些新的名字
                    // 为了方便大批量数据的渲染，配合html文件中的循环渲染，ctemplate类就在TemplateDictionary的定义中，引入了子字典的概念
                    // 有了子字典之后，那所有问题的编号对应的key都可以叫做number，因为它们位于不同的字典中，不会出现重复问题，这就大大节省了空间，也帮我们省了不少事
                
                // 我们在数据字段root内再为当前这个问题，创建一个子字典，名字叫"question_list"
                ctemplate::TemplateDictionary *sub = root.AddSectionDictionary("question_list");
                // 向该字段中插入三个键值对，分别记录当前问题的编号、问题名称、问题难度
                sub->SetValue("number", q.number);
                sub->SetValue("title", q.title);
                sub->SetValue("star", q.star);
            }

            //3. 获取被渲染的html
            ctemplate::Template *tpl = ctemplate::Template::GetTemplate(src_html, ctemplate::DO_NOT_STRIP);
            // GetTemplate用于从文件中加载 HTML 模板，DO_NOT_STRIP：选项表示不自动删除模板中的空白字符（如换行、空格）。

            //4. 开始完成渲染功能
            tpl->Expand(html, &root);
            // Expand将数据字典中的值填充到模板的变量位置，生成最终 HTML 字符串，存储到 html 指针指向的string对象中。
        }

        // 由于我们前面已经将该问题的各个属性信息都存入了struct Question中，因此我们直接用最简单的静态渲染即可
        // OneExpandHtml的功能就是，根据q中的信息，完成对网页的渲染，然后将渲染完成之后的html文件以字符串的形式写入输出型参数html中
        void OneExpandHtml(const struct Question &q, std::string *html)
        {
            // 1. 形成路径
            std::string src_html = template_path + "one_question.html";

            // 2. 形成数字典
            ctemplate::TemplateDictionary root("one_question");
            root.SetValue("number", q.number);
            root.SetValue("title", q.title);
            root.SetValue("star", q.star);
            root.SetValue("desc", q.desc);
            root.SetValue("pre_code", q.header);

            //3. 获取被渲染的html
            ctemplate::Template *tpl = ctemplate::Template::GetTemplate(src_html, ctemplate::DO_NOT_STRIP);
           
            //4. 开始完成渲染功能
            tpl->Expand(html, &root);
        }
    };
}
